/*****************************************************************************
*
*  PROJECT:     Native Executive
*  LICENSE:     See LICENSE in the top level directory
*  FILE:        NativeExecutive/CExecutiveManager.h
*  PURPOSE:     MTA thread and fiber execution manager for workload smoothing
*  DEVELOPERS:  Martin Turski <wordwhirl@outlook.de>
*
*  Multi Theft Auto is available from http://www.multitheftauto.com/
*
*****************************************************************************/

#ifndef _EXECUTIVE_MANAGER_
#define _EXECUTIVE_MANAGER_

#include <sdk/MemoryUtils.h>
#include <sdk/rwlist.hpp>

// Namespace simplification definitions.
#define BEGIN_NATIVE_EXECUTIVE      namespace NativeExecutive {
#define END_NATIVE_EXECUTIVE        }

BEGIN_NATIVE_EXECUTIVE

// Forward declarations.
class CExecThread;
class CFiber;
class CExecTask;

typedef ptrdiff_t threadPluginOffset;

namespace ExecutiveManager
{
    // Function used by the system for performance measurements.
    double GetPerformanceTimer( void );
    
    struct threadPluginInterface
    {
        virtual ~threadPluginInterface( void )       {}

        virtual bool OnPluginConstruct( CExecThread *object, threadPluginOffset pluginOffset, unsigned int pluginId ) = 0;
        virtual void OnPluginDestruct( CExecThread *object, threadPluginOffset pluginOffset, unsigned int pluginId ) = 0;
        virtual bool OnPluginAssign( CExecThread *dstObject, const CExecThread *srcObject, threadPluginOffset pluginOffset, unsigned int pluginid ) = 0;
        virtual void DeleteOnUnregister( void )
        {
            return;
        }
    };
};

// Plugin API definitions.
typedef ExecutiveManager::threadPluginInterface threadPluginInterface;

END_NATIVE_EXECUTIVE

#include "CExecutiveManager.thread.h"
#include "CExecutiveManager.fiber.h"
#include "CExecutiveManager.task.h"
#include "CExecutiveManager.rwlock.h"
#include "CExecutiveManager.cond.h"

BEGIN_NATIVE_EXECUTIVE

#define DEFAULT_GROUP_MAX_EXEC_TIME     16

struct fiberTerminationException
{
    fiberTerminationException( CFiber *fiber )
    {
        this->fiber = fiber;
    }

    CFiber *fiber;
};

class CExecutiveGroup;

class CExecutiveManager abstract
{
public:
    // Public factory API.
    static CExecutiveManager* Create( void );
    static void Delete( CExecutiveManager *manager );

    // USE WITH CAUTION.
    void            PurgeActiveRuntimes ( void );
    void            PurgeActiveThreads  ( void );

    // Plugin API.
    threadPluginOffset    RegisterThreadPlugin( size_t pluginSize, threadPluginInterface *intf );
    void            UnregisterThreadPlugin( threadPluginOffset offset );

    CExecThread*    CreateThread        ( CExecThread::threadEntryPoint_t proc, void *userdata, size_t stackSize = 0 );
    void            TerminateThread     ( CExecThread *thread, bool waitOnRemote = true );
    void            JoinThread          ( CExecThread *thread );
    CExecThread*    GetCurrentThread    ( void );
    CExecThread*    AcquireThread       ( CExecThread *thread );
    void            CloseThread         ( CExecThread *thread );

    unsigned int    GetParallelCapability( void ) const;

    void            CheckHazardCondition( void );

    CFiber*         CreateFiber         ( CFiber::fiberexec_t proc, void *userdata, size_t stackSize = 0 );
    void            TerminateFiber      ( CFiber *fiber );
    void            CloseFiber          ( CFiber *fiber );

    CFiber*         GetCurrentFiber     ( void );

    CExecutiveGroup*    CreateGroup     ( void );

    void            DoPulse             ( void );

    CExecTask*      CreateTask          ( CExecTask::taskexec_t proc, void *userdata, size_t stackSize = 0 );
    void            CloseTask           ( CExecTask *task );

    // Methods for managing synchronization objects.
    // Read/Write locks.
    CReadWriteLock* CreateReadWriteLock ( void );
    void            CloseReadWriteLock  ( CReadWriteLock *theLock );

    size_t          GetReadWriteLockStructSize  ( void );
    CReadWriteLock* CreatePlacedReadWriteLock   ( void *mem );
    void            ClosePlacedReadWriteLock    ( CReadWriteLock *theLock );

    CReentrantReadWriteLock*    CreateReentrantReadWriteLock( void );
    void                        CloseReentrantReadWriteLock ( CReentrantReadWriteLock *theLock );

    size_t                      GetReentrantReadWriteLockStructSize ( void );
    CReentrantReadWriteLock*    CreatePlacedReentrantReadWriteLock  ( void *mem );
    void                        ClosePlacedReentrantReadWriteLock   ( CReentrantReadWriteLock *theLock );

    // Condition variables.
    CCondVar*       CreateConditionVariable ( void );
    void            CloseConditionVariable  ( CCondVar *var );
};

// Helper for lambdas in thread creation.
template <typename callbackType>
AINLINE CExecThread* CreateThreadL( CExecutiveManager *nativeMan, callbackType&& cb, size_t stackSize = 0 )
{
    struct helpers
    {
        static void __stdcall lambda_runtime( CExecThread *thread, void *ud )
        {
            callbackType *cb = (callbackType*)ud;

            try
            {
                (*cb)( thread );
            }
            catch( ... )
            {
                delete cb;

                throw;
            }

            delete cb;
        }
    };

    callbackType *storedLambda = new callbackType( std::move( cb ) );

    return nativeMan->CreateThread( helpers::lambda_runtime, storedLambda, stackSize );
}

// Exception that gets thrown by threads when they terminate.
struct threadTerminationException : public std::exception
{
    inline threadTerminationException( CExecThread *theThread ) : std::exception( "thread termination" )
    {
        this->terminatedThread = theThread;
    }

    inline ~threadTerminationException( void )
    {
        return;
    }

    CExecThread *terminatedThread;
};

class CExecutiveGroup
{
public:
    void AddFiber( CFiber *fiber );

    void SetMaximumExecutionTime( double ms );
    double GetMaximumExecutionTime( void ) const;

    void DoPulse( void );

    void SetPerfMultiplier( double mult );
    double GetPerfMultiplier( void ) const;
};

END_NATIVE_EXECUTIVE

#include "CExecutiveManager.hazards.h"

#endif //_EXECUTIVE_MANAGER_